//  File:	 Calendar.cpp
//  Author:       Scott Nordmann & Lauren Wallace
//  Description:  Non-inline member function definitions.

#include "Calendar.h"
#include "Date.h"
#include "Event.h"
#include "Tag.h"
#include <cstring>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

Calendar::Calendar()
{
	// create today's date to make sure it's in the Calendar for viewing purposes
	Date* d = new Date;
	dates.push_back(d);
}

Calendar::Calendar(ifstream& ifload)
{
	int numDates;

	string dateString;

	Date* date;
	int numEvents;

	Event* e;
	string creatorName;
	string title;
	string content;
	string time;

	ifload >> numDates;

	for (int i = 0; i < numDates; ++i)
	{
		ifload >> dateString;
		date = new Date(Date::parseDate(dateString));

		dates.push_back(date);

		ifload >> numEvents;
		ifload.ignore();

		for (int j = 0; j < numEvents; ++j)
		{
			getline(ifload, creatorName);

			e = new Event(creatorName);

			getline(ifload, title);
			getline(ifload, content);
			getline(ifload, time);

			e->setTitle(title);
			e->setContent(content);

			if (!time.empty())
				e->setTime(time);

			date->addEvent(e);
		}
	}

	// make sure today's date is in the collection
	Date today;

	if (getDate(today) == NULL)
	{
		date = new Date;
		dates.push_back(date);
	}

	sortDates();
}

Calendar::~Calendar()
{
	if (!dates.empty())
	{
		vector<Date*>::iterator i;
		for (i = dates.begin(); i != dates.end(); ++i)
		{
			delete *i;
		}

		dates.clear();
	}
}

void Calendar::shutDown(ofstream& ofsave)
{
	// save only the dates with events- the others can be created on demand
	int numDatesWithEvents = 0;

	vector<Date*>::iterator diter;

	for (diter = dates.begin(); diter != dates.end(); ++diter)
	{
		if ((*diter)->hasEvents())
		{
			numDatesWithEvents++;
		}
	}

	ofsave << numDatesWithEvents << endl;

	for (diter = dates.begin(); diter != dates.end(); ++diter)
	{
		(*diter)->shutDown(ofsave);
	}
}

void Calendar::display()
{
	Date currentDate;
	vector<Date*>::iterator current;
	char week;

	int dateOffset = 0;
	vector<Date*>::iterator viewDate;
	Date view;
	Event* specific;

	do
	{
		current = getDatePos(currentDate);
		displayWeek(current);
	
		cout << "Enter P for previous week, N for next week, V to view a date, Q to quit: ";
		cin >> week;

		switch (toupper(week))
		{
		case 'P':
			currentDate.decrementDay(7);
			break;

		case 'N':
			currentDate.incrementDay(7);
			break;

		case 'V':
			cout << "Enter date number: ";
			cin >> dateOffset;
			--dateOffset;

			view = currentDate;
			view.incrementDay(dateOffset);

			viewDate = getDatePos(view);

			system("cls");
			specific = (*viewDate)->viewSpecificEvent();

			if (specific != NULL)
			{
				system("cls");
				specific->display();
			}

			system("pause");
			break;
			
		default:
			cout << "Invalid selection.";
			break;
		}
		
		system("cls");
	}
	while (toupper(week) != 'Q');
}

Date* Calendar::getDate(int y, int m, int d)
{
	Date dateToGet = Date(y, m, d, -1);
	return *(getDatePos(dateToGet));
}

Date* Calendar::getDate(Date d)
{
	vector<Date*>::iterator pos = getDatePos(d);
	return pos == dates.end() ? NULL : *pos;
}


void Calendar::createEvent(const string& creator)
{
	cout << "Create an Event" << endl << endl;

	string dateString;

	cout << "Enter Date (mm/dd/yyyy): ";
	cin >> dateString;
	cin.ignore();

	// find date in collection using the string
	Date* date = getDate(Date::parseDate(dateString));

	// refresh the screen
	system("cls");
	cout << "New Event on ";
	date->display();
	cout << endl;

	// create a new event
	Event* e = new Event(creator);

	e->populate();

	date->addEvent(e);
}

void Calendar::editEvent()
{
	string dateString;

	cout << "Enter a Date (mm/dd/yyyy): ";
	cin >> dateString;

	Date* date = getDate(Date::parseDate(dateString));

	cout << endl;

	Event* specificEvent = date->viewSpecificEvent();

	if (specificEvent != NULL)
	{
		specificEvent->edit();
	}
}

void Calendar::deleteEvent()
{
	string dateString;

	cout << "Enter a Date (mm/dd/yyyy): ";
	cin >> dateString;

	Date* date = getDate(Date::parseDate(dateString));

	Event* toDelete = date->viewSpecificEvent();

	if (toDelete != NULL)
	{
		char confirm;

		system("cls");
		cout << "Delete Event" << endl << endl;

		toDelete->display();

		cout << "\nDelete this event (y/n)? ";
		cin >> confirm;

		if (toupper(confirm) == 'Y')
		{
			date->deleteEvent(toDelete);
			cout << "\nEvent deleted." << endl;
		}
	}

}

bool Calendar::tagEvent(Tag& currentTag)
{
	bool tagged = false;
	string dateString;
	Date* date;
	Event* toTag;

	cout << "Enter date: ";
	getline(cin, dateString);

	date = getDate(Date::parseDate(dateString));

	toTag = date->viewSpecificEvent();

	if (toTag != NULL)
	{
		toTag->tag(currentTag);
		tagged = true;
	}

	return tagged;
}

bool Calendar::tagEvent(Tag& currentTag, const string& dateString, const string& eventName)
{
	bool tagged = false;
	Date* date;
	Event* toTag;

	date = getDate(Date::parseDate(dateString));

	toTag = date->findEvent(eventName);

	if (toTag != NULL)
	{
		toTag->setDateString(date->getDateString());
		toTag->tag(currentTag);
		tagged = true;
	}
	
	return tagged;
}

Event* Calendar::createMail(const string& creator)
{
	Event* mail = new Event(creator);
	string dateString;
	string recipient;

	cout << "Enter a Date (mm/dd/yyyy): ";
	cin >> dateString;
	cin.ignore();

	cout << dateString;

	mail->setDateString(dateString);

	mail->populate();

	cout << "Enter Recipient name: ";
	getline(cin, recipient);

	mail->setSendTo(recipient);

	return mail;
}
void Calendar::createEvent(Event* e)
{
	Date* date = getDate(Date::parseDate(e->getDateString()));

	date->addEvent(e);
}

void Calendar::displayWeek(vector<Date*>::const_iterator startDate)
{
	cout.fill('-');
	cout << setw(79) << "-" << endl;

	vector<Date*>::const_iterator currentDate = startDate;
	for (int i = 1; i < 8; ++i)
	{
		cout << "[" << i << "] ";
		(*currentDate)->displayEvents();
		currentDate = getNextDate(**currentDate);
	}
}

// tries to find a Date- if it can't find one, it returns dates.end()
vector<Date*>::iterator Calendar::findDate(Date d)
{
	bool found = false;

	vector<Date*>::iterator iter = dates.begin();
	while (!found && iter != dates.end())
	{
		if (**iter == d)
		{
			found = true;
		}
		else
		{
			++iter;
		}
	}

	return iter;
}

// tries to find a Date- if it can't find one, it creates and inserts it
vector<Date*>::iterator Calendar::getDatePos(Date d)
{
	vector<Date*>::iterator dateToGet = findDate(d);

	if (dateToGet == dates.end())
	{
		Date* newDate = new Date(d);

		dates.push_back(newDate);

		sortDates();
		dateToGet = dates.end() - 1;
	}
	
	return dateToGet;
}

vector<Date*>::const_iterator Calendar::getNextDate(const Date& d)
{
	Date temp = d;
	temp.incrementDay();

	vector<Date*>::const_iterator iter = findDate(temp);

	if (iter == dates.end())
	{
		Date* newDate = new Date(temp);
		dates.push_back(newDate);
		sortDates();
		iter = findDate(*newDate);
	}

	return iter;
}

void Calendar::sortDates()
{
	Date* insert;

	for (unsigned short int next = 1; next < dates.size(); ++next)
	{
 		insert = dates[next];

		int moveItem = next;

		while((moveItem > 0) && (*(dates[moveItem - 1]) > *insert))
		{
			dates[moveItem] = dates[moveItem - 1];
			--moveItem;
		}

		dates[moveItem] = insert;
	}
}


